package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.model.CartInfo;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.order.model.OrderDetail;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.SkuInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.unit.DataUnit;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import static com.atguigu.gmall.common.constant.RedisConst.*;

/**
 * @author: atguigu
 * @create: 2023-08-08 10:18
 */
@SuppressWarnings("all")
@Service
public class CartInfoServiceImpl implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 将商品加入到购物车（Redis hash）
     *
     * @param userId 用户ID或者临时用户ID
     * @param skuId  商品ID
     * @param skuNum 商品数量
     * @return
     */
    @Override
    public void addToCart(String userId, Long skuId, int skuNum) {
        //1.先构建用户购物车hash结构的key user:userId:cart
        String cartKey = USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
        //2.创建操作hash结构绑定操作对象 决定该对象操作哪个用户购物车
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);

        //3.判断当前用户购物车中是否存在新增商品
        String hashKey = skuId.toString();
        if (hashOps.hasKey(hashKey)) {
            //3.1 如果商品已经存在购物车中，将数量进行累加
            CartInfo cartInfo = hashOps.get(hashKey);
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            hashOps.put(hashKey, cartInfo);
        } else {
            //3.2 如果商品不存在购物车，进行新增购物车商品即可
            CartInfo cartInfo = new CartInfo();
            //3.2.1 远程调用商品服务获取商品信息-优先从缓存获取
            CompletableFuture<Void> skuInfoCompletableFuture = CompletableFuture.runAsync(() -> {
                SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
                if (skuInfo != null) {
                    //3.2.3 构建购物车商品对象为每个属性赋值
                    cartInfo.setUserId(userId);
                    cartInfo.setSkuName(skuInfo.getSkuName());
                    cartInfo.setSkuId(skuId);
                    cartInfo.setSkuNum(skuNum);
                    cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                    cartInfo.setCreateTime(new Date());
                    cartInfo.setUpdateTime(new Date());
                    cartInfo.setId(skuId);
                }
            }, threadPoolExecutor);
            //3.2.2 远程调用商品服务获取商品最新价格
            CompletableFuture<Void> priceCompletableFuture = CompletableFuture.runAsync(() -> {
                BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
                if (skuPrice != null) {
                    cartInfo.setCartPrice(skuPrice);
                    cartInfo.setSkuPrice(skuPrice);
                }
            }, threadPoolExecutor);
            CompletableFuture.allOf(skuInfoCompletableFuture, priceCompletableFuture).join();
            hashOps.put(hashKey, cartInfo);
        }
    }


    /**
     * 查询用户（临时，登录）购物车列表--不考虑合并
     *
     * @param userId     用户ID
     * @param userTempId 临时用户ID
     * @return
     */
   /* @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //1.先优先获取登录后购物车列表-要对列表进行排序
        if (StringUtils.isNotBlank(userId)) {
            //1.1 构建登录用户购物车hash结构key
            String loginCartKey = RedisConst.USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
            BoundHashOperations<String, String, CartInfo> loginOps = redisTemplate.boundHashOps(loginCartKey);
            //1.2 查询购物车列表
            List<CartInfo> cartInfoList = loginOps.values();
            if (!CollectionUtils.isEmpty(cartInfoList)) {
                //对集合中购物车商品排序 按照新增时间倒序
                List<CartInfo> loginCartList = cartInfoList.stream().sorted((o1, o2) -> {
                    return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
                }).collect(Collectors.toList());
                return loginCartList;
            }
        }
        //2.用户未登录再获取未登录购物车商品列表-要对列表进行排序
        //1.1 构建登录用户购物车hash结构key
        String noLoginCartKey = RedisConst.USER_KEY_PREFIX + userTempId + USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> noLoginOps = redisTemplate.boundHashOps(noLoginCartKey);
        //1.2 查询购物车列表
        List<CartInfo> cartInfoList = noLoginOps.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            //对集合中购物车商品排序 按照新增时间倒序
            List<CartInfo> noLoginCartList = cartInfoList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
            return noLoginCartList;
        }
        return null;
    }*/


    /**
     * 查询用户（临时，登录）购物车列表--合并购物车
     *
     * @param userId     用户ID
     * @param userTempId 临时用户ID
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //1.先尝试获取未登录购物车列表
        List<CartInfo> noLoginCartList = null;
        //1.1 判断临时用户ID是否有值 构建未登录购物车key
        String noLoginKey = USER_KEY_PREFIX + userTempId + USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLoginKey);
        if (StringUtils.isNotBlank(userTempId)) {
            //1.2 查询未登录购物车商品列表，
            noLoginCartList = noLoginHashOps.values();
        }
        //1.3 判断用户未登录，直接返回未登录购物车列表（排序）
        if (StringUtils.isBlank(userId) && !CollectionUtils.isEmpty(noLoginCartList)) {
            noLoginCartList = noLoginCartList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
            return noLoginCartList;
        }

        //2.如果用户登录且未登录购物车列表有数据满足这两个条件才进行合并 遍历未登录购物车列表，判断登录用户hash结构中是否有这件商品
        //2.1 判断未登录购物车是否有数据
        //2.2 构建登录用户购物车key 创建登录购物车hash操作对象
        String loginCartKey = USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> loginHashOps = redisTemplate.boundHashOps(loginCartKey);

        if (!CollectionUtils.isEmpty(noLoginCartList)) {
            //2.3 遍历未登录购物车，判断已登录购物车是否包含未登录购物商品
            noLoginCartList.forEach(noLoginCartInfo -> {
                String hashKey = noLoginCartInfo.getSkuId().toString();
                if (loginHashOps.hasKey(hashKey)) {
                    //2.3.1 如果存在商品，对数量累加更新数量
                    CartInfo loginCartInfo = loginHashOps.get(hashKey);
                    loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + noLoginCartInfo.getSkuNum());
                    loginHashOps.put(hashKey, loginCartInfo);
                } else {
                    //2.3.2 如果不存在商品，则新增（重新指定商品关联用户ID）
                    noLoginCartInfo.setUserId(userId);
                    loginHashOps.put(hashKey, noLoginCartInfo);
                }
            });
        }
        //3.合并后将未登录购物车清理
        redisTemplate.delete(noLoginKey);

        //4.合并成功后，再次查询登录购物车商品列表（排序）
        List<CartInfo> cartInfoList = loginHashOps.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList.stream().sorted((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getCreateTime(), o1.getCreateTime(), Calendar.SECOND);
            }).collect(Collectors.toList());
            return cartInfoList;
        }
        return null;
    }

    /**
     * 修改购物车商品选中状态
     *
     * @param userId
     * @param skuId
     * @param isChecked
     * @return
     */
    @Override
    public void checkCart(String userId, Long skuId, int isChecked) {
        //1.构建用户购物车key
        String cartKey = USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
        //2.获取到购物车商品 修改选中状态
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        String hashKey = skuId.toString();
        if (hashOps.hasKey(hashKey)) {
            CartInfo cartInfo = hashOps.get(hashKey);
            cartInfo.setIsChecked(isChecked);
            hashOps.put(hashKey, cartInfo);
        }
    }

    /**
     * 删除用户购物车中商品
     *
     * @param request
     * @param skuId
     * @return
     */
    @Override
    public void deleteCart(String userId, Long skuId) {
        //1.构建用户购物车key
        String cartKey = USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
        //2.获取到购物车商品 修改选中状态
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        String hashKey = skuId.toString();
        if (hashOps.hasKey(hashKey)) {
            hashOps.delete(hashKey);
        }
    }

    /**
     * 根据用户ID，查询用户购物车商品，将CartInfo转为OrderDetail对象
     *
     * @param userId
     * @return
     */
    @Override
    public List<OrderDetail> getCartCheckedList(Long userId) {
        //1.构建用户购物车key
        String cartKey = USER_KEY_PREFIX + userId + USER_CART_KEY_SUFFIX;
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        //2.获取当前用户所有选中购物车商品列表
        List<CartInfo> allCartInfoList = hashOps.values();

        //3.将集合类型从CartInfo转为OrderInfo
        if (!CollectionUtils.isEmpty(allCartInfoList)) {
            List<OrderDetail> orderDetailList = allCartInfoList.stream().filter((cartInfo -> {
                return cartInfo.getIsChecked().intValue() == 1;
            })).map(cartInfo -> {
                OrderDetail orderDetail = new OrderDetail();
                orderDetail.setSkuId(cartInfo.getSkuId());
                orderDetail.setImgUrl(cartInfo.getImgUrl());
                orderDetail.setSkuName(cartInfo.getSkuName());
                orderDetail.setSkuNum(cartInfo.getSkuNum());
                orderDetail.setOrderPrice(cartInfo.getSkuPrice());
                return orderDetail;
            }).collect(Collectors.toList());
            return orderDetailList;
        }
        return null;
    }
}
